//
// Created by pzw on 24-1-4.
//

#include "ThreadPool.h"

/**
 * the constructor just launches some amount of workers
 *
 * @param threads 线程个数
 */
__attribute__((unused)) inline ThreadPool::ThreadPool(size_t threads) : stop(false) {
    for (size_t i = 0; i < threads; ++i) {
        workers.emplace_back([this] {
            for (;;) {
                std::function<void()> task;
                {
                    std::unique_lock<std::mutex> lock(this->queue_mutex);
                    this->condition.wait(lock, [this] {
                        return this->stop || !this->tasks.empty();
                    });
                    if (this->stop && this->tasks.empty()) {
                        return;
                    }
                    task = std::move(this->tasks.front());
                    this->tasks.pop();
                }

                task();
            }
        });
    }
}

/**
 * add new work item to the pool: 这个函数相当牛逼, 理解之前请参阅DecltypeResultOf.h中的介绍.
 *
 * @tparam F    F
 * @tparam Args DecltypeResultOf
 * @param f     F的实例
 * @param args  Args的实例
 * @return std::future<typename std::result_of<F(Args...)>::type>
 */
template<class F, class... Args>
auto ThreadPool::enqueue(F &&f, Args &&... args) -> std::future<typename std::result_of<F(Args...)>::type> {
    using return_type = typename std::result_of<F(Args...)>::type;

    auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );

    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);

        // don't allow enqueueing after stopping the pool
        if (stop) { throw std::runtime_error("enqueue on stopped ThreadPool"); }

        tasks.emplace([task]() { (*task)(); });
    }
    condition.notify_one();
    return res;
}

/**
 * the destructor joins all threads
 *
 * 析构函数
 */
inline ThreadPool::~ThreadPool() {
    {
        std::unique_lock<std::mutex> lock(queue_mutex);
        stop = true;
    }
    condition.notify_all();
    for (std::thread &worker: workers) { worker.join(); }
}

/**
 * add new work item to the pool
 *
 * @tparam F    - 可调用对象
 * @tparam Args - 可调用对象的参数
 * @param f     - F的实例
 * @param args  - Args的实例
 * @return       std::future<typename std::result_of<F(Args...)>::type>
 */
template<class F, class... Args>
std::future<typename std::result_of<F(Args...)>::type> ThreadPool::enqueue2(F &&f, Args &&... args) {
    using return_type = typename std::result_of<F(Args...)>::type;

    auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...)
    );

    std::future<return_type> res = task->get_future();
    {
        std::unique_lock<std::mutex> lock(queue_mutex);

        // don't allow enqueueing after stopping the pool
        if (stop) { throw std::runtime_error("enqueue on stopped ThreadPool"); }

        tasks.emplace([task]() { (*task)(); });
    }
    condition.notify_one();
    return res;
}

